package com.study.chunguard.common.utils.geo;

import java.util.List;

/**
 * 判断经纬度是否在一个范围区域内
 *
 * @author : Lei
 * @since : 2021-05-07
 **/
public class PointUtil {

    private PointUtil() {
        throw new IllegalStateException("Utility class");
    }

    private static final double EARTH_RADIUS = 6378137;

    /**
     * 判断一点是否在多边形内
     *
     * @param target 目标点
     * @param points 多边形的顶点
     * @return 是否在多边形内
     */
    public static boolean isPointInPolygon(LatLonPoint target, List<LatLonPoint> points) {
        int iSum;
        int iCount;
        int iIndex;
        int minSize = 3;
        double dLon1;
        double dLon2;
        double dLat1;
        double dLat2;
        double dLon;
        if (points.size() < minSize) {
            return false;
        }
        iSum = 0;
        iCount = points.size();
        for (iIndex = 0; iIndex < iCount; iIndex++) {
            if (iIndex == iCount - 1) {
                dLon1 = points.get(iIndex).getLongitude();
                dLat1 = points.get(iIndex).getLatitude();
                dLon2 = points.get(0).getLongitude();
                dLat2 = points.get(0).getLatitude();
            } else {
                dLon1 = points.get(iIndex).getLongitude();
                dLat1 = points.get(iIndex).getLatitude();
                dLon2 = points.get(iIndex + 1).getLongitude();
                dLat2 = points.get(iIndex + 1).getLatitude();
            }

            double latitude = target.getLatitude();
            double longitude = target.getLongitude();
            // 以下语句判断A点是否在边的两端点的水平平行线之间，在则可能有交点，开始判断交点是否在左射线上
            if (((latitude >= dLat1) && (latitude < dLat2)) || ((latitude >= dLat2) && (latitude < dLat1)) && (Math.abs(dLat1 - dLat2) > 0)) {
                // 得到 A点向左射线与边的交点的x坐标：
                dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - latitude)) / (dLat1 - dLat2);
                // 如果交点在A点左侧（说明是做射线与 边的交点），则射线与边的全部交点数加一：
                if (dLon < longitude) {
                    iSum++;
                }

            }
        }
        return (iSum % 2) != 0;
    }

    /**
     * 计算两个经纬度之间的距离，单位为米
     *
     * @param lat1 起始纬度
     * @param lng1 起始经度
     * @param lat2 结束纬度
     * @param lng2 结束经度
     * @return 距离，单位为米
     */
    public static double getDistance(double lat1, double lng1, double lat2,
                                     double lng2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        return s;
    }

    /**
     * @param d 经纬度
     * @return 距离
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }
}
